import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import org.identityconnectors.common.security.GuardedString;

class BoxGuardedString {
    BoxGuardedString(GuardedString s) {
        theString = s;
    }
    public GuardedString theString;
}

class BoxInt {
    BoxInt(int i) {
        theInt = i;
    }
    public int theInt;
}

class BoxCharArray {
    BoxCharArray(char[] a) {
        theArray = a;
    }
    public char[] theArray;
}

class PasswordItemDetails {
//    public SecureString ssAccount { get; set; }
//    public SecureString ssURLstring { get; set; }
//    public SecureString ssLogin { get; set; }
//    public uint index { get; set; }
//    public static string emptystring = "";
//
//    public string Account { get { return (this.ssAccount == null) ? emptystring : this.ssAccount.ToInsecureString(); } set { this.ssAccount = value.ToSecureString(); } }
//    public string URLstring { get { return (this.ssURLstring == null) ? emptystring : this.ssURLstring.ToInsecureString(); } set { this.ssURLstring = value.ToSecureString(); } }
//    public string Login { get { return (this.ssLogin == null) ? emptystring : this.ssLogin.ToInsecureString(); } set { this.ssLogin = value.ToSecureString(); } }
//
//    public string DisplayName { get { return String.Format("Account {0}: {1}", index, this.Account); } }
//
//    public PasswordItemDetails (uint i)
//    {
//        index = i;
//    }
    public GuardedString ssAccount;
    public GuardedString ssURLstring;
    public GuardedString ssLogin;
    public PasswordItemDetails(GuardedString account, GuardedString url, GuardedString login) {
        ssAccount = account;
        ssURLstring = url;
        ssLogin = login;
    }

    public String toString() {
        //return ssAccount.toString();
//        char[] chs;
//        String str;
        class M {
            String s;
        }
        M m = new M();
        ssAccount.access(new GuardedString.Accessor() {
            @Override
            public void access(char[] chars) {
                //chs = chars;
                m.s = new String(chars);
            }
        });

        return m.s;
    }
}

public class MainWindow extends JFrame implements ListSelectionListener {

    static {
        System.loadLibrary("PasswordManagerCoreImpl");
    }

    boolean bCreateNewVault = false;

    private JButton buttonOpen;

    PasswordManagerCore mgr = new PasswordManagerCore();
    private JFrame frame;
    private JPanel panelUnlock;
    private JButton buttonUnlock;
    private JPasswordField txtpasswordbox;
    private DefaultListModel<PasswordItemDetails> itemDetails;

    MainWindow() {
        super("Password Manager");
        //setSize(753, 700);

        frame = this;

        buildUI();
        bindEventToMethod();

        // 让窗口位于屏幕中间
        Dimension dim = getToolkit().getScreenSize();
        setLocation(dim.width/2 - getWidth()/2,
                dim.height/2 - getHeight()/2);

        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    private void bindEventToMethod() {
        buttonOpen.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                OpenExistingVault();
            }
        });

        buttonUnlock.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                unlock_Click();
            }
        });

    }

    private  void unlock_Click() {
        int count = 0;
        GuardedString randpass = new GuardedString();
        GuardedString emptypass = new GuardedString();
        GuardedString ssname = new GuardedString();
        GuardedString login = new GuardedString();
        GuardedString url = new GuardedString();
        GuardedString accountpass = new GuardedString();
        GuardedString masterpass;
        int rv = 0;

        masterpass = new GuardedString(txtpasswordbox.getPassword());
        if (masterpass.equals("")) {
            JOptionPane.showMessageDialog(null, "Please enter Master Password to Unlock the vault: ");
            return;
        }

        if (bCreateNewVault) {
            rv = mgr.set_master_password(masterpass, masterpass);
            if (rv != PasswordManagerStatus.OK) {
                JOptionPane.showMessageDialog(null, "Setting master password failed: " + returnErrorcode(rv));
                return;
            }
        }
        else {
            // 关键代码
            rv = mgr.vault_unlock(masterpass);
            if (rv != PasswordManagerStatus.OK) {
                JOptionPane.showMessageDialog(null, "Couldn't unlock vault: " + returnErrorcode(rv));
                return;
            }
        }
        this.txtpasswordbox.setText("");
        masterpass.dispose();
        //pmangerPanel.Visibility = Visibility.Collapsed;

        BoxInt boxCount = new BoxInt(count);
        rv = mgr.accounts_get_count(boxCount);
        count = boxCount.theInt;
        if (rv != PasswordManagerStatus.OK) {
            JOptionPane.showMessageDialog(null, "Couldn't get number of accounts from password vault: " + returnErrorcode(rv));
            return;
        }

        if (!bCreateNewVault) {

            for (int i = 0; i < count; ++i) {

                BoxGuardedString boxSsname = new BoxGuardedString(ssname);
                BoxGuardedString boxLogin = new BoxGuardedString(login);
                BoxGuardedString boxUrl = new BoxGuardedString(url);
                rv = mgr.accounts_get_info(i, boxSsname, boxLogin, boxUrl);
                ssname = boxSsname.theString;
                login = boxLogin.theString;
                url = boxUrl.theString;
                if (rv != PasswordManagerStatus.OK) {
                    JOptionPane.showMessageDialog(null, "Failed getting account info: " + returnErrorcode(rv));
                    return;
                }

                itemDetails.addElement(new PasswordItemDetails( ssname, url, login));
            }
        }

        // 列表项不够8个也要用空的补够8个
        for (int i = count; i < 8; ++i) {
            //itemDetails.Add(new PasswordItemDetails(i));
        }

//        lbPasswordList.ItemsSource = itemDetails;
//        lbPasswordList.Background = SystemColors.ControlLightLightBrush;
//        lbPasswordList.SelectedItem = lbPasswordList.Items.GetItemAt(0);
//        btnEditAccount.IsEnabled = true;
//        btnViewPassword.IsEnabled = true;
//        btnCopyPassword.IsEnabled = true;
//        mnCopyto.IsEnabled = true;
//        btnCreateVault.IsEnabled = false;
//        btnOpenVault.IsEnabled = false;
//        mnOpen.IsEnabled = false;
//        mnNew.IsEnabled = false;
//        btnlock.IsEnabled = true;
//        mnLock.IsEnabled = true;
//        btnUnlock.IsEnabled = false;
//        mnChangePassword.IsEnabled = true;
//        this.btnViewPassword.Content = "View Password";

    }

    private void OpenExistingVault() {
        //JOptionPane.showMessageDialog(null, "hi");
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(null);
        chooser.setFileFilter(new FileFilter() {

            public String getDescription() {
                return "Vault (*.vlt)";
            }

            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                } else {
                    String filename = f.getName().toLowerCase();
                    return filename.endsWith(".vlt");
                }
            }
        });

        if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION)
            return;
        File file = chooser.getSelectedFile();

        String path = file.getPath();

        int rv = mgr.vault_open(path);
        if (rv != PasswordManagerStatus.OK)
        {
            JOptionPane.showMessageDialog(null, "Failed opening vault file: " + returnErrorcode(rv));
            return;
        }

//                working_vault = path;
        //pmangerPanel.Visibility = Visibility.Visible;
        panelUnlock.setVisible(true);
        frame.pack();
    }

    private void buildUI() {
        JMenu menuFile = new JMenu("File");
        JMenu menuVault = new JMenu("Vault");
        JMenu menuTools = new JMenu("Tools");
        //file.add(fileExit);
        JMenuBar mb = new JMenuBar();
        mb.add(menuFile);
        mb.add(menuVault);
        mb.add(menuTools);
        setJMenuBar(mb);


        Container contentPane = getContentPane();
        //contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));

        JPanel panelManager = new JPanel();
        panelManager.setBorder(BorderFactory.createTitledBorder("Password Manager"));
        contentPane.add(panelManager, BorderLayout.NORTH);

        panelManager.setLayout(new BoxLayout(panelManager, BoxLayout.Y_AXIS));
        JPanel panelOpenCreate = new JPanel();
        panelManager.add(panelOpenCreate);
        panelUnlock = new JPanel();
        //panelUnlock.setVisible(false);
        panelManager.add(panelUnlock);

        buttonOpen = new JButton("Open Password Vault");
        panelOpenCreate.add(buttonOpen);
        JButton buttonCreate = new JButton("Create New Vault");
        panelOpenCreate.add(buttonCreate);

        panelUnlock.setLayout(new BorderLayout());
        panelUnlock.add(new JLabel("Enter your Master Password to Unlock your Vault"), BorderLayout.WEST);
        txtpasswordbox = new JPasswordField("", 30);
        panelUnlock.add(txtpasswordbox, BorderLayout.CENTER);
        buttonUnlock = new JButton("Unlock");
        panelUnlock.add(buttonUnlock, BorderLayout.EAST);


        JPanel panelVault = new JPanel();
        panelVault.setBorder(BorderFactory.createTitledBorder("Password Vault"));
        contentPane.add(panelVault, BorderLayout.CENTER);
        panelVault.setLayout(new BorderLayout());

        itemDetails = new DefaultListModel<PasswordItemDetails>();
//        listModel.addElement(new PasswordItemDetails(new GuardedString("Jane Doe".toCharArray()), new GuardedString("".toCharArray()), new GuardedString("".toCharArray())));
//        listModel.addElement(new PasswordItemDetails(new GuardedString("John Smith".toCharArray()), new GuardedString("".toCharArray()), new GuardedString("".toCharArray())));
//        listModel.addElement(new PasswordItemDetails(new GuardedString("Kathy Green".toCharArray()), new GuardedString("".toCharArray()), new GuardedString("".toCharArray())));


        JList list = new JList(itemDetails);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);
        list.addListSelectionListener(this);
        list.setVisibleRowCount(6);
        JScrollPane scrollPaneList = new JScrollPane(list);
        panelVault.add(scrollPaneList, BorderLayout.CENTER);

        JPanel panelDetailAndButtons = new JPanel();
        panelVault.add(panelDetailAndButtons, BorderLayout.SOUTH);

        panelDetailAndButtons.setLayout(new BoxLayout(panelDetailAndButtons, BoxLayout.Y_AXIS));
        JPanel panelDetail = new JPanel();
        JPanel panelButtons = new JPanel();
        panelDetailAndButtons.add(panelDetail);
        panelDetailAndButtons.add(panelButtons);

        panelDetail.setLayout(new BorderLayout());
        JPanel panelLabels = new JPanel();
        panelDetail.add(panelLabels, BorderLayout.WEST);
        JPanel panelTextField = new JPanel();
        panelDetail.add(panelTextField, BorderLayout.CENTER);

        panelLabels.setLayout(new GridLayout(3, 1, 5, 5));
        panelTextField.setLayout(new GridLayout(3, 1, 5, 5));

        panelLabels.add(new JLabel("Account Name:"));
        panelLabels.add(new JLabel("URL:"));
        panelLabels.add(new JLabel("Login / Username:"));

        JTextField textFieldAccount = new JTextField();
        panelTextField.add(textFieldAccount);
        JTextField textFieldUrl = new JTextField();
        panelTextField.add(textFieldUrl);
        JTextField textFieldUsername = new JTextField();
        panelTextField.add(textFieldUsername);

        JButton buttonEdit = new JButton("Edit Account");
        panelButtons.add(buttonEdit);
        JButton buttonView = new JButton("View Password");
        panelButtons.add(buttonView);
        JButton buttonCopy = new JButton("Copy Password");
        panelButtons.add(buttonCopy);


        JButton buttonLock = new JButton("Lock Vault");
        buttonLock.setSize(200, 40);
        Panel panelLock = new Panel(); // 没这一层panel, buttonLock就会占满一行
        panelLock.add(buttonLock);
        contentPane.add(panelLock, BorderLayout.SOUTH);

        pack();
        panelUnlock.setVisible(false);
    }


    @Override
    public void valueChanged(ListSelectionEvent e) {
//        JFileChooser chooser = new JFileChooser();
//        chooser.setCurrentDirectory(null);
//        if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION)
//            return;
//        File file = chooser.getSelectedFile();
    }

    public enum PasswordDisplayStatus
    {
        BadFile(10),
        CantUpdate(15),
        Clipboard(14),
        Exists(5),
        IncorrectVersion(9),
        Invalid(8),
        MemoryAllocation(2),
        NoChange(1),
        NoPermission(6),
        NotFound(7),
        OK(0),
        PasswordIncorrect(13),
        RandomGenerator(11),
        Range(4),
        Size(3),
        UserCancelled(12),
        WriteFailed(16);

        private int id; // Could be other data type besides int
        private PasswordDisplayStatus(int id) {
            this.id = id;
        }

        public int getId() {
            return this.id;
        }

        public static PasswordDisplayStatus fromId(int id) {
            for (PasswordDisplayStatus type : values()) {
                if (type.getId() == id) {
                    return type;
                }
            }
            return null;
        }
    }

    public static String returnErrorcode(int rv)
    {

        PasswordDisplayStatus passDisplayStatus = PasswordDisplayStatus.fromId(rv);
        String stringValue;
        if (passDisplayStatus != null)
            stringValue = passDisplayStatus.toString();
        else
            stringValue = String.valueOf(rv);

        return stringValue;
    }
}
